#include"cd_object.h"
#include"cd_stack.h"
#include"cd_string.h"
#include"cd_int.h"
#include"be_alloc.h"
#include"be_utility.h"

CD_NAMESPACE_BEGIN


class	c_string_def:public	c_entity{
public:

private:

};

static	c_string_def	g_string_def;
static	c_object	g_string_def_obj=c_object(&g_string_def,
					c_object::OBJ_TYPE_CONST);

c_string::c_string(s32	len)
	:m_bgn(0),m_len(0),m_cap(len>0?len:1)
{
	m_val	=	(s8*)be::alloc::allocate(len);
}

c_string::c_string(const	s8*	str, s32 len)
	:m_bgn(0),m_len(len),m_cap(len>0?len:1)
{
	m_val	=	(s8*)be::alloc::allocate(len);
	memmove(m_val,	str,	len);
}

c_string::~c_string()
{
	be::alloc::deallocate(m_val,	m_cap);
}

s32		c_string::reset(const	s8*	str, s32 len)
{
	if(m_cap<len){
		return	-1;
	}
	memmove(m_val, str, len);
	m_bgn	=	0;
	m_len	=	len;
	return	0;
}

const	s8*	c_string::type_name(	)
{
	return	"string";
}


s64		c_string::hash(	)
{
		s32	i	=	0;
		s8*	s	=	m_val;
		s64 h	=	0; 
		s	=	m_val	+	m_bgn;
		for (; i	<	m_len; ++i,++s)
			h = 5*h + *s;

		return s64(h);
}

c_object*	c_string::type(	)
{
	return	&g_string_def_obj;
}

c_object*	c_string::get_member(const s8* name)
{
	c_object*	ret	=	NULL;


	return	ret;
}

c_object*	c_string::get_member(s32 index)
{
	c_object*	ret	=	NULL;


	return	ret;
}

c_entity*	c_string::deep_copy(c_stack*	stack)
{
	return	new	c_string(m_val,	m_len);
}

static	inline	s32	i_stack_get(c_stack*	stack,	
	c_string*&	ts,	c_string*&	i)
{
	s32			ret	=	en_sucess;
	c_object*	ol	=	stack->get_ths_reg();
	assert(ol);
	ts	=	(c_string*)ol->entity();
	c_object*	or	=	stack->argu(0);
	if(!or){
		stack->throw_exception(EXCP_INVALID_ADDR);
		return	en_invalid_addr;
	}
	c_entity*	ent	=	or->entity();
	if(!ent){
		stack->throw_exception(EXCP_NULL_ARGU);
		return	en_null_argu;	
	}
	i	=	dynamic_cast<c_string*>(ent);
	if(!i){
		stack->throw_exception(EXCP_INVALID_OP_TYPE);
		return	en_invalid_type;			
	}
	return	ret;
}

static	inline	s32	i_stack_get(c_stack*	stack,	
	c_string*&	ts,	c_int*&	i)
{
	s32			ret	=	en_sucess;
	c_object*	ol	=	stack->get_ths_reg();
	assert(ol);
	ts	=	(c_string*)ol->entity();
	c_object*	or	=	stack->argu(0);
	if(!or){
		stack->throw_exception(EXCP_INVALID_ADDR);
		return	en_invalid_addr;
	}
	c_entity*	ent	=	or->entity();
	if(!ent){
		stack->throw_exception(EXCP_NULL_ARGU);
		return	en_null_argu;	
	}
	i	=	dynamic_cast<c_int*>(ent);
	if(!i){
		stack->throw_exception(EXCP_INVALID_OP_TYPE);
		return	en_invalid_type;			
	}
	return	ret;
}

static	inline	s32	i_stack_get(c_stack*	stack,	
	c_string*&	ts,	c_entity*&	i)

{
	s32			ret	=	en_sucess;
	c_object*	ol	=	stack->get_ths_reg();
	assert(ol);
	ts	=	(c_string*)ol->entity();
	c_object*	or	=	stack->argu(0);
	if(!or){
		stack->throw_exception(EXCP_INVALID_ADDR);
		return	en_invalid_addr;
	}
	i	=	or->entity();
	if(!i){
		stack->throw_exception(EXCP_NULL_ARGU);
		return	en_null_argu;	
	}
	return	ret;
}
s32		c_string::s_adde(c_stack*	stack)
{
	s32			ret	=	en_sucess;
	c_string*	ts	=	NULL;
	c_string*	i	=	NULL;
	s8*			tmp	=	NULL;
	s32			len	=	0;
	ret	=	i_stack_get(stack,	ts,	i);
	if(ret	<	0){
		return	ret;
	}
	len	=	ts->m_len	+	i->m_len;
	if(ts->m_cap	<	len)
	{
		tmp	=	(s8*)be::alloc::allocate(len);
		if(!tmp){
			stack->throw_exception(EXCP_CONSTRUCT_FAIL);
			return	en_cnstrct_fail;
		}
		memmove(tmp, ts->m_val+ts->m_bgn,	ts->m_len);
		be::alloc::deallocate(ts->m_val,	ts->m_cap);
		ts->m_val	=	tmp;
		ts->m_bgn	=	0;
	}else	if(ts->m_cap - ts->m_bgn < len){
		memmove(ts->m_val, ts->m_val+ts->m_bgn, ts->m_len);
		ts->m_bgn	=	0;
	}

	memmove(ts->m_val+ts->m_bgn+ts->m_len,
				i->m_val+i->m_bgn,i->m_len);
	ts->m_cap	+=	i->m_len;
	stack->set_ireg(ts->m_cap);
	stack->set_sreg(ts->m_val);
	return	ret;
}
s32		c_string::s_add(c_stack*	stack)
{
	s32			ret	=	en_sucess;
	s32			len	=	0;
	c_string*	ts	=	NULL;
	c_string*	i	=	NULL;
	c_object*	ir	=	stack->get_ret_reg();
	ret	=	i_stack_get(stack,	ts,	i);
	if(ret	<	0){
		return	ret;
	}
	len	=	ts->m_len	+	i->m_len;
	c_string*		s	=	new	c_string(len);
	if(!s){
		stack->throw_exception(EXCP_CONSTRUCT_FAIL);
		return	en_cnstrct_fail;
	}

	memmove(s->m_val, ts->m_val + ts->m_bgn, ts->m_len);
	memmove(s->m_val + ts->m_len, i->m_val + i->m_bgn, i->m_len);
	s->m_len	=	len;
	assert(ir);
	ir->set_ent(s);
	stack->set_ireg(s->m_len);
	stack->set_sreg(s->m_val);
	return	ret;
}

s32		c_string::s_ele(c_stack*		stack)
{
	s32			ret	=	en_sucess;
	c_string*	ts	=	NULL;
	c_int*		i	=	NULL;
	c_object*	ir	=	stack->get_ret_reg();
	ret	=	i_stack_get(stack,	ts,	i);
	if(ret	<	0){
		return	ret;
	}
	s32	index	=	(s32)i->value();
	if(index	<	0	||	index	>=	ts->m_len){
		stack->throw_exception(EXCP_OUT_RANGE);
		return	en_out_range;
	}
	s8		c	=	ts->m_val[ts->m_bgn	+	index];
	c_int*		s	=	new	c_int(c);
	if(!s){
		stack->throw_exception(EXCP_CONSTRUCT_FAIL);
		return	en_cnstrct_fail;
	}

	assert(ir);
	ir->set_ent(s);
	stack->set_ireg(c);
	return	ret;
}
s32		c_string::s_split(c_stack*	stack)
{
	s32			ret	=	en_sucess;
	c_string*	ts	=	NULL;
	c_int*		i	=	NULL;
	c_object*	ir	=	stack->get_ret_reg();
	ret	=	i_stack_get(stack,	ts,	i);
	if(ret	<	0){
		return	ret;
	}
	s32	index	=	(s32)i->value();
	if(index	<	0	||	index	>=	ts->m_len){
		stack->throw_exception(EXCP_OUT_RANGE);
		return	en_out_range;
	}
	c_string*	s	=	new	c_string(ts->m_val
				+ts->m_bgn+index,ts->m_len-index);
	if(!s){
		stack->throw_exception(EXCP_CONSTRUCT_FAIL);
		return	en_cnstrct_fail;
	}

	ts->m_len	=	index;

	assert(ir);
	ir->set_ent(s);
	stack->set_ireg(index);
	return	ret;
}

s32		c_string::s_find(c_stack*		stack)
{
	s32			ret	=	en_sucess;
	c_string*	ts	=	NULL;

	c_int*		i	=	NULL;
	c_string*	s	=	NULL;
	c_object*	ir	=	stack->get_ret_reg();
	ret	=	i_stack_get(stack,	ts,	i);
	if(ret	<	0){
		return	ret;
	}
	return	ret;
}

void*	c_string::operator new(size_t	sz)
{
	return	be::alloc::allocate(sz);
}
void	c_string::operator delete(void*	pt,size_t	sz)
{
	return	be::alloc::deallocate(pt,	sz);
}

CD_NAMESPACE_END